# coding:utf-8
import commands
import logging
import os
import re
import shutil
import traceback

import time
from pexpect import *

from app.modules.apps.container import ContainerApp
from app.modules.common import network
from config import BeetleConfig

log = logging.getLogger(__name__)


# 封装基于apache的PHP应用系统.
class HttpdPhpApp(ContainerApp):
    def __init__(self, app_id, app_name, zone_home_path, zone_alias, port,
                 sub_doc_dir = '', nas_app_package_path = None,
                 container_home = '/usr/local/soft/apache'):

        super(HttpdPhpApp, self).__init__(app_id = app_id, app_name = app_name,
                                          zone_home_path = zone_home_path,
                                          zone_alias = zone_alias, port = port,
                                          nas_app_package_path = nas_app_package_path,
                                          container_home = container_home)

        if nas_app_package_path is None:
            self._nas_app_package_path = '/mnt/winitRelease/latest.product/' + self._app_name

        self._httpd_vhost_file_name = self._container_home + '/conf/extra/httpd-vhosts.conf'

        self._app_conf_file_name = self._container_home + '/conf/extra/apps/%s.conf' % self._app_zone_alias
        self._app_conf_relative_path = 'conf/extra/apps/%s.conf' % self._app_zone_alias

        self._app_home_path = zone_home_path + '/php_' + app_name

        # Httpd的Directory的自路径, 一般与app_home_path一致, 有时则需要再指定一层子目录.
        self._sub_doc_dir = sub_doc_dir
        self._directory_path = self._app_home_path + self._sub_doc_dir

        # httpd的端口号是由apache管理的, 不用占用
        self._ports = []

    def set_runtime_param(self, nas_app_package = None, version = '', sub_path = ''):

        super(HttpdPhpApp, self).set_runtime_param(
            nas_app_package = nas_app_package, version = version,
            sub_path = sub_path)

        log.info(self._version)

    def validate(self):

        # check httpd

        # check app

        # check nas package

        pass

    def install_app(self):
        self.download_app_package()
        self._create_conf_file()
        # self.include_conf_file()
        self._config_app()

    def uninstall_app(self):
        self.remove_conf_file()
        # self.remove_app_from_vhosts()
        self.remove_app_home()

    def restart(self):
        self.run('killall -9 httpd', timeout = 10)
        self.run(
            '/bin/bash -c "ipcs -s | perl -ane \'/^0x00000000/ '
            '&& `ipcrm -s $F[1]`\'"')

        time.sleep(2)
        self.run('service httpd start', timeout = 10)
        time.sleep(2)

    def stop(self):

        self.remove_conf_file()
        self.restart()

    def _config_app(self):

        self._update_config()

        if not os.path.isdir(self._app_config_home_path):
            msg = '没有找到配置文件, svn/winit2.0/config/UC 目录下没有该应用的配置文件?'
            raise Exception(msg)

        # self.run(
        #     '/bin/bash -c "cd %s;svn revert -R ./ ;svn up;"' % self._app_config_home_path)

        _log, _result = self.run('/bin/bash -c "cp -rf %s/* %s"' % (
            self._app_config_home_path, self._app_home_path))

        print _result

        self.extend_config()

        self.run('chown -R beetle %s' % self._app_home_path)

    def is_started(self, accurately = False):
        return network.is_open(self._port)

    # 从vhosts文件中, 移除引用的conf文件.
    def remove_app_from_vhosts(self):
        with open(self._httpd_vhost_file_name, 'r') as _f:
            _content = _f.read()

        _result = re.sub(
            r'(\r*\n*)(Include)(\s*)(.*%s\.conf)' % self._app_zone_alias, '',
            _content)
        # print _result
        with open(self._httpd_vhost_file_name, 'w') as _f:
            _f.write(_result)

        self.app_log(
            '%s has benn removed from vhostfile... ' % self._app_name + ':' + self._port)

    # 删除某个区域-应用的conf文件.
    def remove_conf_file(self):
        if os.path.isfile(self._app_conf_file_name):
            os.remove(self._app_conf_file_name)
        self.app_log('Config file "%s" has been removed. ')

    # 删除app的安装包目录.
    def remove_app_home(self):
        self.validate()

        shutil.rmtree(self._app_home_path, ignore_errors = True)

        self.app_log('App home has been removed.%s' % self._app_home_path)

    # 创建某个应用的conf文件
    def _create_conf_file(self):

        self.run('mkdir -p %s' % self._container_home + '/conf/extra/apps')
        _value = '\n' \
                 + 'Listen %s' % self._port + '\n' \
                 + '<VirtualHost *:%s>' % self._port + '\n'
        if self._app_name == 'tom':
            _value = _value + '\tSSLEngine on' + '\n' \
                     + '\tSSLCertificateFile /usr/local/soft/nginx/ssl/server.crt' + '\n' \
                     + '\tSSLCertificateKeyFile /usr/local/soft/nginx/ssl/server.key' + '\n'

        _value = _value + '\tServerAdmin webmaster@winit.com.cn' + '\n' \
                 + '\t' + r'DocumentRoot "%s"' % self._directory_path + '\n' \
                 + '\tServerName %s.winit.com.cn' % self._app_zone_alias + '\n' \
                 + '\t' + r'ErrorLog "%s/%s.log"' % (
                     BeetleConfig.APP_LOG_PATH, self._app_id) + '\n' \
                 + '\t' + r'CustomLog "%s/%s.log" common' % (
                     BeetleConfig.APP_LOG_PATH, self._app_id) + '\n' \
                 + '\t' + r'<Directory "%s" >' % self._directory_path + '\n' \
                 + '\t\tOptions FollowSymLinks' + '\n' \
                 + '\t\tAllowOverride ALL' + '\n' \
                 + '\t\tOrder allow,deny' + '\n' \
                 + '\t\tAllow from all' + '\n' \
                 + '\t' r'</Directory>' + '\n'

        if self._app_name == 'developer':
            _value = _value + '\t' + r'<Directory "%s/uploads" >' % self._directory_path + '\n' \
                     + '\t\tOptions FollowSymLinks' + '\n' \
                     + '\t\tAllowOverride ALL' + '\n' \
                     + '\t\tOrder allow,deny' + '\n' \
                     + '\t\tAllow from all' + '\n' \
                     + '\t' r'</Directory>' + '\n'

        _value = _value + r'</VirtualHost>' + '\n'
        with open(self._app_conf_file_name, 'wb') as _file:
            _file.write(_value)

        self.app_log('%s has been created.' % self._app_conf_file_name)

    # 将应用的conf文件包含到vhost文件中.
    def include_conf_file(self):
        # self.remove_app_from_vhosts()

        if not os.path.isfile(self._app_conf_file_name) or not os.path.isfile(
                self._httpd_vhost_file_name):
            raise Exception(
                self._app_conf_file_name + ' or ' + self._httpd_vhost_file_name + ' do not exists!');

        with open(self._httpd_vhost_file_name, 'ab') as _f:
            _f.write('\nInclude %s' % self._app_conf_relative_path)

        self.app_log(
            'A new app conf file %s has benn add in vhostfile... ' % self._app_name + ':' + self._port)

    def download_app_package(self):

        self.validate()

        if not os.path.exists(self._app_home_path):
            self.app_log(run('mkdir -p %s' % self._app_home_path))
            self.app_log(log)

        _nas_package = self._nas_app_package_path + self._sub_path

        # 一段脏代码, 处理海外仓的SMQ代码与国内不一致的特殊情况.
        if (self._app_name == 'SMQ' or self._app_name == 'smq') \
                and re.search("gzidc", self._zone_home_path,
                              re.M) is None:
            # 海外版扫描枪的路径为/SMQ_OS,只有在应用是smq且zone不是中国时才用它.
            _nas_package += '_OS'
            self.run(
                command = '/bin/bash -c "cp -f %s %s" ' % (
                    _nas_package + '/*.zip', self._app_home_path + '/SMQ.zip'),
                raise_on_error = True)

        else:
            self.run(
                command = '/bin/bash -c "cp -f %s %s" ' % (
                    _nas_package + '/*.zip', self._app_home_path),
                raise_on_error = True)

        # 解压
        self.run(command = '/bin/bash -c "unzip -oq *.zip"',
                 cwd = self._app_home_path, raise_on_error = True)
        self.run(command = '/bin/bash -c "rm -f *.zip"', cwd = self._app_home_path)

        self.app_log('Package %s has been downloaded to %s' % (
            self._nas_app_package_path, self._app_home_path))
        # 删除缓存
        if self._app_name == 'tom':
            self.run(
                command = '/bin/bash -c "rm -rf %s/Apps/Runtime/*" ' % self._app_home_path,
                raise_on_error = True)
        elif self._app_name == 'sellerportal':
            self.run(
                command = '/bin/bash -c "rm -rf %s/Manage/Runtime/*" ' % self._app_home_path,
                raise_on_error = True)

    def extend_config(self):
        if self._app_name == 'tom':

            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(\n\s*'CAS_HOST'\s*=>\s*')(.*)(',)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)
            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(\n\s*'WEBSOCKET_HOST'\s*=>\s*')(.*)(',)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)
            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(\n\s*'WEBDAV_SERVER'\s*=>\s*')(.*)(',)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)

        elif self._app_name == 'sellerportal':
            self.replace_config_content(
                file_path = self._app_home_path + '/Conf/config.php',
                pattern = r"(.*'EDS'|'OPC'|'OPC_API'|'HELP'|'BOOKING'|'JX'|'TRACKING'|'COUPON')"
                          r"(\s*=>\s*'http://|\s*=>\s*'https://)(.*)(:\d*.*)",
                repl = r"\g<1>\g<2>%s\g<4>" % self._local_ip)

            self.replace_config_content(
                file_path = self._app_home_path + '/Conf/config.php',
                pattern = r"('COOKIE_DOMAIN'\s*=>\s*')(.*)('\s*,.*)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)

            self.run(command = "sed -i '/^\s*$/d' %s/Manage/.htaccess" % self._app_home_path)
            self.run(command = "sed -i '/RewriteBase/,+2d' %s/Manage/.htaccess" % self._app_home_path)
            self.run(command = 'mkdir -p %s/Upload/Excels' % self._app_home_path)
            if os.path.isdir(BeetleConfig.CONTAINER_TEMPLATE_PATH):
                log.warn(
                    "sellerportal的excel模板路径 %s 没有找到, 跳过这个步骤会导致下载功能无法测试." % BeetleConfig.CONTAINER_TEMPLATE_PATH)
                return

            _sellerportal_template_path = BeetleConfig.CONTAINER_TEMPLATE_PATH + '/php_sellerportal'

            self.run(
                command = '/bin/bash -c "\cp -rf %s %s" ' % (
                    _sellerportal_template_path + '/*', self._app_home_path),
                raise_on_error = False)


        elif self._app_name == 'eds':
            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(.*'MANAGE'|'OPC_API'|'HELP'|"
                          r"'BOOKING'|'JX'|'TRACKING'|'COUPON')"
                          r"(\s*=>\s*'http://)(.*)(:\d*.*)",
                repl = r"\g<1>\g<2>%s\g<4>" % self._local_ip)

            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"('COOKIE_DOMAIN'\s*=>\s*')(.*)('\s*,.*)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)

            self.run(command = "sed -i '/RewriteBase/,+2d' %s/.htaccess" % self._app_home_path)

        elif self._app_name == 'help':
            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(.*'MANAGE'|'OPC_API'|'HELP'|"
                          r"'BOOKING'|'JX'|'TRACKING'|'COUPON')"
                          r"(\s*=>\s*'http://)(.*)(:\d*.*)",
                repl = r"\g<1>\g<2>%s\g<4>" % self._local_ip)

            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"('COOKIE_DOMAIN'\s*=>\s*')(.*)('\s*,.*)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)

            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(\n\s*'WEBDAV_SERVER'\s*=>\s*')(.*)(',)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)

        elif self._app_name == 'jinxuan':
            self.replace_config_content(
                file_path = self._app_home_path + '/Apps/Common/Conf/config.php',
                pattern = r"(\n\s*'WEBDAV_SERVER'\s*=>\s*')(.*)(',)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)
        elif self._app_name == 'upush2-console-ui':
            self.replace_config_content(
                file_path = self._app_home_path + '/config/config.js',
                pattern = r"(.*http://)(127.0.0.1)(:\d*.*)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)
        elif self._app_name == 'cloudlink-epc-ui':
            self.replace_config_content(
                file_path = self._app_home_path + '/conf/config.js',
                pattern = r"(.*http://)(127.0.0.1)(:\d*.*)",
                repl = r"\g<1>%s\g<3>" % self._local_ip)
        else:
            pass
